home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / fontutil.6 / fontutil / fontutils-0.6 / widgets / Viewport.c < prev   
Encoding:
C/C++ Source or Header  |  1992-09-02  |  30.5 KB  |  946 lines

  1. /* Viewport.c: implementation of the Athena Viewport widget.  The
  2.    geometry manager has been modified from the distributed version.
  3.  
  4. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  5. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  6.  
  7.                         All Rights Reserved
  8.  
  9. Permission to use, copy, modify, and distribute this software and its 
  10. documentation for any purpose and without fee is hereby granted, 
  11. provided that the above copyright notice appear in all copies and that
  12. both that copyright notice and this permission notice appear in 
  13. supporting documentation, and that the names of Digital or MIT not be
  14. used in advertising or publicity pertaining to distribution of the
  15. software without specific, written prior permission.  
  16.  
  17. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  18. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  19. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  20. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  22. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  23. SOFTWARE.
  24.  
  25. ******************************************************************/
  26.  
  27. #include <X11/IntrinsicP.h>
  28. #include <X11/StringDefs.h>
  29.  
  30. #include <X11/Xaw/XawInit.h>
  31. #include <X11/Xmu/Misc.h>
  32. #include <X11/Xaw/Scrollbar.h>
  33. #include <X11/Xaw/ViewportP.h>
  34.  
  35. static void ScrollUpDownProc(), ThumbProc();
  36. static Boolean GetGeometry();
  37.  
  38. #define offset(field) XtOffset(ViewportWidget,viewport.field)
  39. static XtResource resources[] = {
  40.     {XtNforceBars, XtCBoolean, XtRBoolean, sizeof(Boolean),
  41.      offset(forcebars), XtRImmediate, (caddr_t)False},
  42.     {XtNallowHoriz, XtCBoolean, XtRBoolean, sizeof(Boolean),
  43.      offset(allowhoriz), XtRImmediate, (caddr_t)False},
  44.     {XtNallowVert, XtCBoolean, XtRBoolean, sizeof(Boolean),
  45.      offset(allowvert), XtRImmediate, (caddr_t)False},
  46.     {XtNuseBottom, XtCBoolean, XtRBoolean, sizeof(Boolean),
  47.      offset(usebottom), XtRImmediate, (caddr_t)False},
  48.     {XtNuseRight, XtCBoolean, XtRBoolean, sizeof(Boolean),
  49.      offset(useright), XtRImmediate, (caddr_t)False},
  50. };
  51. #undef offset
  52.  
  53. static void Initialize(), ConstraintInitialize(),
  54.     Realize(), Resize(), ChangeManaged();
  55. static Boolean SetValues(), Layout();
  56. static void ComputeLayout();
  57. static XtGeometryResult GeometryManager(), PreferredGeometry();
  58.  
  59. #define superclass    (&formClassRec)
  60. ViewportClassRec viewportClassRec = {
  61.   { /* core_class fields */
  62.     /* superclass      */    (WidgetClass) superclass,
  63.     /* class_name      */    "Viewport",
  64.     /* widget_size      */    sizeof(ViewportRec),
  65.     /* class_initialize      */    XawInitializeWidgetSet,
  66.     /* class_part_init    */    NULL,
  67.     /* class_inited      */    FALSE,
  68.     /* initialize      */    Initialize,
  69.     /* initialize_hook    */    NULL,
  70.     /* realize          */    Realize,
  71.     /* actions          */    NULL,
  72.     /* num_actions      */    0,
  73.     /* resources      */    resources,
  74.     /* num_resources      */    XtNumber(resources),
  75.     /* xrm_class      */    NULLQUARK,
  76.     /* compress_motion      */    TRUE,
  77.     /* compress_exposure  */    TRUE,
  78.     /* compress_enterleave*/    TRUE,
  79.     /* visible_interest      */    FALSE,
  80.     /* destroy          */    NULL,
  81.     /* resize          */    Resize,
  82.     /* expose          */    XtInheritExpose,
  83.     /* set_values      */    SetValues,
  84.     /* set_values_hook    */    NULL,
  85.     /* set_values_almost  */    XtInheritSetValuesAlmost,
  86.     /* get_values_hook    */    NULL,
  87.     /* accept_focus      */    NULL,
  88.     /* version            */    XtVersion,
  89.     /* callback_private      */    NULL,
  90.     /* tm_table          */    NULL,
  91.     /* query_geometry     */    PreferredGeometry,
  92.     /* display_accelerator*/    XtInheritDisplayAccelerator,
  93.     /* extension          */    NULL
  94.   },
  95.   { /* composite_class fields */
  96.     /* geometry_manager      */    GeometryManager,
  97.     /* change_managed      */    ChangeManaged,
  98.     /* insert_child      */    XtInheritInsertChild,
  99.     /* delete_child      */    XtInheritDeleteChild,
  100.     /* extension          */    NULL
  101.   },
  102.   { /* constraint_class fields */
  103.     /* subresourses      */    NULL,
  104.     /* subresource_count  */    0,
  105.     /* constraint_size      */    sizeof(ViewportConstraintsRec),
  106.     /* initialize      */    ConstraintInitialize,
  107.     /* destroy          */    NULL,
  108.     /* set_values      */    NULL,
  109.     /* extension          */    NULL
  110.   },
  111.   { /* form_class fields */
  112.     /* layout          */    Layout
  113.   },
  114.   { /* viewport_class fields */
  115.     /* empty          */    0
  116.   }
  117. };
  118.  
  119.  
  120. WidgetClass viewportWidgetClass = (WidgetClass)&viewportClassRec;
  121.  
  122. static Widget CreateScrollbar(w, horizontal)
  123.     ViewportWidget w;
  124.     Boolean horizontal;
  125. {
  126.     Widget clip = w->viewport.clip;
  127.     ViewportConstraints constraints =
  128.     (ViewportConstraints)clip->core.constraints;
  129.     static Arg barArgs[] = {
  130.     {XtNorientation, (XtArgVal) NULL},
  131.     {XtNlength, (XtArgVal) NULL},
  132.     {XtNleft, (XtArgVal) NULL},
  133.     {XtNright, (XtArgVal) NULL},
  134.     {XtNtop, (XtArgVal) NULL},
  135.     {XtNbottom, (XtArgVal) NULL},
  136.     {XtNmappedWhenManaged, False},
  137.     };
  138.     Widget bar;
  139.  
  140.     XtSetArg(barArgs[0], XtNorientation,
  141.           horizontal ? XtorientHorizontal : XtorientVertical );
  142.     XtSetArg(barArgs[1], XtNlength,
  143.          horizontal ? clip->core.width : clip->core.height);
  144.     XtSetArg(barArgs[2], XtNleft,
  145.          (!horizontal && w->viewport.useright) ? XtChainRight : XtChainLeft);
  146.     XtSetArg(barArgs[3], XtNright,
  147.          (!horizontal && !w->viewport.useright) ? XtChainLeft : XtChainRight);
  148.     XtSetArg(barArgs[4], XtNtop,
  149.          (horizontal && w->viewport.usebottom) ? XtChainBottom: XtChainTop);
  150.     XtSetArg(barArgs[5], XtNbottom,
  151.          (horizontal && !w->viewport.usebottom) ? XtChainTop: XtChainBottom);
  152.  
  153.     bar = XtCreateWidget( (horizontal ? "horizontal" : "vertical"),
  154.               scrollbarWidgetClass, (Widget)w,
  155.               barArgs, XtNumber(barArgs) );
  156.     XtAddCallback( bar, XtNscrollProc, ScrollUpDownProc, (caddr_t)w );
  157.     XtAddCallback( bar, XtNjumpProc, ThumbProc, (caddr_t)w );
  158.  
  159.     if (horizontal) {
  160.     w->viewport.horiz_bar = bar;
  161.     constraints->form.vert_base = bar;
  162.     }
  163.     else {
  164.     w->viewport.vert_bar = bar;
  165.     constraints->form.horiz_base = bar;
  166.     }
  167.  
  168.     XtManageChild( bar );
  169.  
  170.     return bar;
  171. }
  172.  
  173. /* ARGSUSED */
  174. static void Initialize(request, new)
  175.     Widget request, new;
  176. {
  177.     ViewportWidget w = (ViewportWidget)new;
  178.     static Arg clip_args[5];
  179.     Cardinal num_args;
  180.     Widget h_bar, v_bar;
  181.     Dimension clip_height, clip_width;
  182.  
  183.     w->form.default_spacing = 0;  /* Reset the default spacing to 0 pixels. */
  184.  
  185.  
  186. /* 
  187.  * Initialize all widget pointers to NULL.
  188.  */
  189.  
  190.     w->viewport.child = (Widget) NULL;
  191.     w->viewport.horiz_bar = w->viewport.vert_bar = (Widget)NULL;
  192.  
  193. /* 
  194.  * Create Clip Widget.
  195.  */
  196.  
  197.     num_args = 0;
  198.     XtSetArg(clip_args[num_args], XtNborderWidth, 0); num_args++;
  199.     XtSetArg(clip_args[num_args], XtNleft, XtChainLeft); num_args++;
  200.     XtSetArg(clip_args[num_args], XtNright, XtChainRight); num_args++;
  201.     XtSetArg(clip_args[num_args], XtNtop, XtChainTop); num_args++;
  202.     XtSetArg(clip_args[num_args], XtNbottom, XtChainBottom); num_args++;
  203.  
  204.     w->viewport.clip = XtCreateManagedWidget("clip", widgetClass, new,
  205.                          clip_args, num_args);
  206.  
  207.  
  208.     if (!w->viewport.forcebars) 
  209.         return;         /* If we are not forcing the bars then we are done. */
  210.  
  211.     if (w->viewport.allowhoriz) 
  212.         (void) CreateScrollbar(w, True);
  213.     if (w->viewport.allowvert) 
  214.         (void) CreateScrollbar(w, False);
  215.  
  216.     h_bar = w->viewport.horiz_bar;
  217.     v_bar = w->viewport.vert_bar;
  218.  
  219. /*
  220.  * Set the clip widget to the correct height.
  221.  */
  222.  
  223.     clip_width = w->core.width;
  224.     clip_height = w->core.height;
  225.  
  226.     if ( (h_bar != NULL) &&
  227.      (w->core.width > h_bar->core.width + h_bar->core.border_width) )
  228.         clip_width -= h_bar->core.width + h_bar->core.border_width;
  229.     
  230.     if ( (v_bar != NULL) &&
  231.      (w->core.height > v_bar->core.height + v_bar->core.border_width) )
  232.         clip_height -= v_bar->core.height + v_bar->core.border_width;
  233.  
  234.     num_args = 0;
  235.     XtSetArg(clip_args[num_args], XtNwidth, clip_width); num_args++;
  236.     XtSetArg(clip_args[num_args], XtNheight, clip_height); num_args++;
  237.     XtSetValues(w->viewport.clip, clip_args, num_args);
  238. }
  239.  
  240. /* ARGSUSED */
  241. static void ConstraintInitialize(request, new)
  242.     Widget request, new;
  243. {
  244.     ((ViewportConstraints)new->core.constraints)->viewport.reparented = False;
  245. }
  246.  
  247. static void Realize(widget, value_mask, attributes)
  248.     Widget widget;
  249.     XtValueMask *value_mask;
  250.     XSetWindowAttributes *attributes;
  251. {
  252.     ViewportWidget w = (ViewportWidget)widget;
  253.     register Widget child = w->viewport.child;
  254.     register Widget clip = w->viewport.clip;
  255.  
  256.     *value_mask |= CWBitGravity;
  257.     attributes->bit_gravity = NorthWestGravity;
  258.     (*superclass->core_class.realize)(widget, value_mask, attributes);
  259.  
  260.     ComputeLayout( widget, /*query=*/True, /*destroy=*/True );
  261.  
  262.     if (child != (Widget)NULL) {
  263.     XtMoveWidget( child, (Position)0, (Position)0 );
  264.     XtRealizeWidget( clip );
  265.     XtRealizeWidget( child );
  266.     XReparentWindow( XtDisplay(w), XtWindow(child), XtWindow(clip),
  267.              (Position)0, (Position)0 );
  268.     XtMapWidget( child );
  269.     }
  270. }
  271.  
  272. /* ARGSUSED */
  273. static Boolean SetValues(current, request, new)
  274.     Widget current, request, new;
  275. {
  276.     ViewportWidget w = (ViewportWidget)new;
  277.     ViewportWidget cw = (ViewportWidget)current;
  278.  
  279.     if (w->viewport.forcebars != cw->viewport.forcebars) {
  280.     if (w->viewport.forcebars) {
  281.         if (w->viewport.allowhoriz && w->viewport.horiz_bar == (Widget)NULL)
  282.         (void) CreateScrollbar( w, True );
  283.         if (w->viewport.allowvert && w->viewport.vert_bar == (Widget)NULL)
  284.         (void) CreateScrollbar( w, False );
  285.     }
  286.     }
  287.  
  288.     /* take care of bars, &tc. */
  289.     ComputeLayout( w, /*query=*/True, /*destroy=*/True );
  290.     return False;
  291. }
  292.  
  293.  
  294. static void ChangeManaged(widget)
  295.     Widget widget;
  296. {
  297.     ViewportWidget w = (ViewportWidget)widget;
  298.     register int num_children = w->composite.num_children;
  299.     register Widget child, *childP;
  300.     register int i;
  301.  
  302.     child = (Widget)NULL;
  303.     for (childP=w->composite.children, i=0; i < num_children; childP++, i++) {
  304.     if (XtIsManaged(*childP)
  305.         && *childP != w->viewport.clip
  306.         && *childP != w->viewport.horiz_bar
  307.         && *childP != w->viewport.vert_bar)
  308.     {
  309.         child = *childP;
  310.         break;
  311.     }
  312.     }
  313.  
  314.     if (child != w->viewport.child) {
  315.     w->viewport.child = child;
  316.     if (child != (Widget)NULL) {
  317.         XtResizeWidget( child, child->core.width,
  318.                 child->core.height, (Dimension)0 );
  319.         if (XtIsRealized(widget)) {
  320.         ViewportConstraints constraints =
  321.             (ViewportConstraints)child->core.constraints;
  322.         if (!XtIsRealized(child)) {
  323.             Window window = XtWindow(w);
  324.             XtMoveWidget( child, (Position)0, (Position)0 );
  325. #ifdef notdef
  326.             /* this is dirty, but it saves the following code: */
  327.             XtRealizeWidget( child );
  328.             XReparentWindow( XtDisplay(w), XtWindow(child),
  329.                      XtWindow(w->viewport.clip),
  330.                      (Position)0, (Position)0 );
  331.             if (child->core.mapped_when_managed)
  332.             XtMapWidget( child );
  333. #else 
  334.             w->core.window = XtWindow(w->viewport.clip);
  335.             XtRealizeWidget( child );
  336.             w->core.window = window;
  337. #endif /* notdef */
  338.             constraints->viewport.reparented = True;
  339.         }
  340.         else if (!constraints->viewport.reparented) {
  341.             XReparentWindow( XtDisplay(w), XtWindow(child),
  342.                      XtWindow(w->viewport.clip),
  343.                      (Position)0, (Position)0 );
  344.             constraints->viewport.reparented = True;
  345.             if (child->core.mapped_when_managed)
  346.             XtMapWidget( child );
  347.         }
  348.         }
  349.         GetGeometry( widget, child->core.width, child->core.height );
  350.         (*((ViewportWidgetClass)w->core.widget_class)->form_class.layout)
  351.         ( (FormWidget)w, w->core.width, w->core.height );
  352.         /* %%% do we need to hide this child from Form?  */
  353.     }
  354.     }
  355.  
  356. #ifdef notdef
  357.     (*superclass->composite_class.change_managed)( widget );
  358. #endif
  359. }
  360.  
  361.  
  362. static void SetBar(w, top, length, total)
  363.     Widget w;
  364.     Position top;
  365.     Dimension length, total;
  366. {
  367.     XawScrollbarSetThumb(w, (float) top / total, (float) length / total );
  368. }
  369.  
  370. static void RedrawThumbs(w)
  371.   ViewportWidget w;
  372. {
  373.     register Widget child = w->viewport.child;
  374.     register Widget clip = w->viewport.clip;
  375.  
  376.     if (w->viewport.horiz_bar != (Widget)NULL)
  377.     SetBar( w->viewport.horiz_bar, -(child->core.x),
  378.             clip->core.width, child->core.width );
  379.  
  380.     if (w->viewport.vert_bar != (Widget)NULL)
  381.     SetBar( w->viewport.vert_bar, -(child->core.y),
  382.             clip->core.height, child->core.height );
  383. }
  384.  
  385.  
  386.  
  387. static void MoveChild(w, x, y)
  388.     ViewportWidget w;
  389.     Position x, y;
  390. {
  391.     register Widget child = w->viewport.child;
  392.     register Widget clip = w->viewport.clip;
  393.  
  394.     /* make sure we never move past right/bottom borders */
  395.     if (-x + clip->core.width > child->core.width)
  396.     x = -(child->core.width - clip->core.width);
  397.  
  398.     if (-y + clip->core.height > child->core.height)
  399.     y = -(child->core.height - clip->core.height);
  400.  
  401.     /* make sure we never move past left/top borders */
  402.     if (x >= 0) x = 0;
  403.     if (y >= 0) y = 0;
  404.  
  405.     XtMoveWidget(child, x, y);
  406.  
  407.     RedrawThumbs(w);
  408. }
  409.  
  410.  
  411. static void ComputeLayout(widget, query, destroy_scrollbars)
  412.     Widget widget;        /* Viewport */
  413.     Boolean query;        /* query child's preferred geom? */
  414.     Boolean destroy_scrollbars;    /* destroy un-needed scrollbars? */
  415. {
  416.     ViewportWidget w = (ViewportWidget)widget;
  417.     register Widget child = w->viewport.child;
  418.     register Widget clip = w->viewport.clip;
  419.     ViewportConstraints constraints
  420.     = (ViewportConstraints)clip->core.constraints;
  421.     Boolean needshoriz, needsvert;
  422.     Dimension clip_width, clip_height;
  423.     XtWidgetGeometry intended;
  424.     static void ComputeWithForceBars();
  425.  
  426.     if (child == (Widget) NULL) return;
  427.  
  428.     clip_width = w->core.width;
  429.     clip_height = w->core.height;
  430.     intended.request_mode = CWBorderWidth;
  431.     intended.border_width = 0;
  432.  
  433.     if (w->viewport.forcebars) {
  434.         needsvert = w->viewport.allowvert;
  435.         needshoriz = w->viewport.allowhoriz;
  436.         ComputeWithForceBars(widget, query, &intended, 
  437.                  &clip_width, &clip_height);
  438.     }
  439.     else {
  440.     XtWidgetGeometry preferred;
  441.         XtGeometryResult result;
  442.  
  443.         needshoriz = needsvert = False;
  444.  
  445.         if (query) {
  446.             /* First get the child's preferred width and height.  */
  447.             intended.width = child->core.width;
  448.             intended.height = child->core.height;
  449.             intended.request_mode = CWWidth | CWHeight;
  450.             (void) XtQueryGeometry( child, &intended, &preferred );
  451.             if ( !(preferred.request_mode & CWWidth) )
  452.             preferred.width = intended.width;
  453.         if ( !(preferred.request_mode & CWHeight) )
  454.             preferred.height = intended.height;
  455.             
  456.         } else {
  457.             /* We can't ask the child, so just take whatever it is.  */
  458.             preferred.width = intended.width = child->core.width;
  459.             preferred.height = intended.height = child->core.height;
  460.         }
  461.  
  462.         /* See if the parent will accept this.  */
  463.         result = query
  464.                  ? XtMakeResizeRequest ((Widget) w,
  465.                                         preferred.width, preferred.height,
  466.                                         &clip_width, &clip_height)
  467.                  : XtGeometryNo;
  468.         if (result != XtGeometryYes) {
  469.             if (result == XtGeometryAlmost)
  470.                 XtMakeResizeRequest ((Widget) w, clip_width,
  471.                                      clip_height, NULL, NULL); 
  472.  
  473.             /* The parent didn't go for it (at least completely), or we
  474.                weren't supposed to ask.  See if we have scrollbars enabled.  */
  475. #define CheckHoriz()                              \
  476.         if (w->viewport.allowhoriz && preferred.width > clip_width) { \
  477.             if (!needshoriz) {                      \
  478.             Widget bar;                              \
  479.                     Dimension bar_height;                  \
  480.             needshoriz = True;                          \
  481.             if ((bar = w->viewport.horiz_bar) == (Widget)NULL)    \
  482.                 bar = CreateScrollbar(w, True);                  \
  483.                     bar_height = bar->core.height + bar->core.border_width;\
  484.                     /* If possible, increase the height to account for       \
  485.                        the width's scrollbar.  */              \
  486.                     if (query && preferred.height == clip_height)      \
  487.                       {                              \
  488.                         Dimension almost_h;                  \
  489.                         result                          \
  490.                           = XtMakeResizeRequest ((Widget) w, w->core.width,\
  491.                                                     w->core.height      \
  492.                                                     + bar_height,      \
  493.                                                     NULL, &almost_h);      \
  494.                         if (result == XtGeometryAlmost)              \
  495.                           XtMakeResizeRequest ((Widget) w,          \
  496.                                      w->core.width, almost_h, NULL, NULL);\
  497.                       }                              \
  498.                     clip_height = w->core.height - bar_height;          \
  499.             if (clip_height < 1) clip_height = 1;          \
  500.         }                              \
  501.             intended.width = preferred.width;              \
  502.         }
  503. /*enddef*/
  504.         CheckHoriz();
  505.         if (w->viewport.allowvert && preferred.height > clip_height) {
  506.             if (!needsvert) {
  507.             Widget bar;
  508.                     Dimension bar_width;
  509.                     
  510.             needsvert = True;
  511.             if ((bar = w->viewport.vert_bar) == (Widget)NULL)
  512.                 bar = CreateScrollbar(w, False);
  513.                     bar_width = bar->core.width + bar->core.border_width;
  514.                     /* Now that we have a Scrollbar for the height, we
  515.                        should see if we can get back the width we lost.  */
  516.             if (query && preferred.width == clip_width)
  517.                       {
  518.                         Dimension almost_w;
  519.                         result
  520.                           = XtMakeResizeRequest ((Widget) w,
  521.                                                  preferred.width + bar_width,
  522.                                                  preferred.height,
  523.                                                  &almost_w, NULL); 
  524.                         if (result == XtGeometryAlmost)
  525.                             XtMakeResizeRequest ((Widget) w,
  526.                                                  almost_w, w->core.height,
  527.                                                  NULL, NULL);
  528.                       }
  529.                     clip_width = w->core.width - bar_width;
  530.             if (clip_width < 1) clip_width = 1;
  531.                     
  532.             CheckHoriz();
  533.         }
  534.         intended.height = preferred.height;
  535.         }
  536.             
  537.             /* If we don't have scrollbars enabled, then the child
  538.                loses.  */
  539.         }
  540.     }
  541.  
  542.     if (XtIsRealized(clip))
  543.     XRaiseWindow( XtDisplay(clip), XtWindow(clip) );
  544.  
  545.     XtMoveWidget( clip,
  546.           needsvert ? (w->viewport.useright ? 0 :
  547.                    w->viewport.vert_bar->core.width +
  548.                    w->viewport.vert_bar->core.border_width) : 0,
  549.           needshoriz ? (w->viewport.usebottom ? 0 :
  550.                 w->viewport.horiz_bar->core.height +
  551.                     w->viewport.horiz_bar->core.border_width) : 0);
  552.     XtResizeWidget( clip, (Dimension)clip_width,
  553.             (Dimension)clip_height, (Dimension)0 );
  554.     
  555.     if (w->viewport.horiz_bar != (Widget)NULL) {
  556.     register Widget bar = w->viewport.horiz_bar;
  557.     if (!needshoriz) {
  558.         constraints->form.vert_base = (Widget)NULL;
  559.         if (destroy_scrollbars) {
  560.         XtDestroyWidget( bar );
  561.         w->viewport.horiz_bar = (Widget)NULL;
  562.         }
  563.     }
  564.     else {
  565.         register int bw = bar->core.border_width;
  566.         XtResizeWidget( bar, clip_width, bar->core.height, bw );
  567.         XtMoveWidget( bar,
  568.               ((needsvert && !w->viewport.useright)
  569.                ? w->viewport.vert_bar->core.width
  570.                : -bw),
  571.               (w->viewport.usebottom
  572.                 ? w->core.height - bar->core.height - bw
  573.                 : -bw) );
  574.         XtSetMappedWhenManaged( bar, True );
  575.     }
  576.     }
  577.  
  578.     if (w->viewport.vert_bar != (Widget)NULL) {
  579.     register Widget bar = w->viewport.vert_bar;
  580.     if (!needsvert) {
  581.         constraints->form.horiz_base = (Widget)NULL;
  582.         if (destroy_scrollbars) {
  583.         XtDestroyWidget( bar );
  584.         w->viewport.vert_bar = (Widget)NULL;
  585.         }
  586.     }
  587.     else {
  588.         register int bw = bar->core.border_width;
  589.         XtResizeWidget( bar, bar->core.width, clip_height, bw );
  590.         XtMoveWidget( bar,
  591.               (w->viewport.useright
  592.                ? w->core.width - bar->core.width - bw 
  593.                : -bw),
  594.               ((needshoriz && !w->viewport.usebottom)
  595.                 ? w->viewport.horiz_bar->core.height
  596.                 : -bw) );
  597.         XtSetMappedWhenManaged( bar, True );
  598.     }
  599.     }
  600.  
  601.     if (child != (Widget)NULL) {
  602.     XtResizeWidget( child, (Dimension)intended.width,
  603.                 (Dimension)intended.height, (Dimension)0 );
  604.     MoveChild(w,
  605.           needshoriz ? child->core.x : 0,
  606.           needsvert ? child->core.y : 0);
  607.     }
  608. }
  609.  
  610. /*      Function Name: ComputeWithForceBars
  611.  *      Description: Computes the layout give forcebars is set.
  612.  *      Arguments: widget - the viewport widget.
  613.  *                 query - whether or not to query the child.
  614.  *                 intended - the cache of the childs height is
  615.  *                            stored here ( USED AND RETURNED ).
  616.  *                 clip_width, clip_height - size of clip window.
  617.  *                                           (USED AND RETURNED ).
  618.  *      Returns: none.
  619.  */
  620.  
  621. static void
  622. ComputeWithForceBars(widget, query, intended, clip_width, clip_height)
  623. Widget widget;
  624. Boolean query;
  625. XtWidgetGeometry * intended;
  626. int *clip_width, *clip_height;
  627. {
  628.     ViewportWidget w = (ViewportWidget)widget;
  629.     register Widget child = w->viewport.child;
  630.     XtWidgetGeometry preferred;
  631.  
  632. /*
  633.  * If forcebars then needs = allows = has.
  634.  * Thus if needsvert is set it MUST have a scrollbar.
  635.  */
  636.  
  637.     if (w->viewport.allowvert)
  638.         *clip_width -= w->viewport.vert_bar->core.width +
  639.                       w->viewport.vert_bar->core.border_width;
  640.  
  641.     if (w->viewport.allowhoriz)
  642.         *clip_height -= w->viewport.horiz_bar->core.height +
  643.                w->viewport.horiz_bar->core.border_width;
  644.  
  645.     AssignMax( *clip_width, 1 );
  646.     AssignMax( *clip_height, 1 );
  647.  
  648.     if (!w->viewport.allowvert) {
  649.         intended->height = *clip_height;
  650.         intended->request_mode = CWHeight;
  651.     }
  652.     if (!w->viewport.allowhoriz) {
  653.         intended->width = *clip_width;
  654.         intended->request_mode = CWWidth;
  655.     }
  656.  
  657.     if ( query ) {
  658.         if ( (w->viewport.allowvert || w->viewport.allowhoriz) ) { 
  659.         XtQueryGeometry( child, intended, &preferred );
  660.       
  661.         if ( !(intended->request_mode & CWWidth) )
  662.             if ( preferred.request_mode & CWWidth )
  663.             intended->width = preferred.width;
  664.         else
  665.             intended->width = child->core.width;
  666.  
  667.         if ( !(intended->request_mode & CWHeight) )
  668.             if ( preferred.request_mode & CWHeight )
  669.             intended->height = preferred.height;
  670.         else
  671.             intended->height = child->core.height;
  672.     }
  673.     }
  674.     else {
  675.         if (w->viewport.allowvert)
  676.         intended->height = child->core.height;
  677.     if (w->viewport.allowhoriz)
  678.         intended->width = child->core.width;
  679.     }
  680.  
  681.     AssignMax(intended->width, *clip_width);
  682.     AssignMax(intended->height, *clip_height);
  683. }
  684.  
  685. static void Resize(widget)
  686.     Widget widget;
  687. {
  688.     ComputeLayout( widget, /*query=*/False, /*destroy=*/True );
  689. }
  690.  
  691.  
  692. /* ARGSUSED */
  693. static Boolean Layout(w, width, height)
  694.     FormWidget w;
  695.     Dimension width, height;
  696. {
  697.     ComputeLayout( (Widget)w, /*query=*/True, /*destroy=*/True );
  698.     w->form.preferred_width = w->core.width;
  699.     w->form.preferred_height = w->core.height;
  700.     return False;
  701. }
  702.  
  703.  
  704. static void ScrollUpDownProc(widget, closure, call_data)
  705.     Widget widget;
  706.     caddr_t closure;
  707.     caddr_t call_data;
  708. {
  709.     ViewportWidget w = (ViewportWidget)closure;
  710.     register Widget child = w->viewport.child;
  711.     int pix = (int)call_data;
  712.     Position x, y;
  713.  
  714.     if (child == NULL) return;    /* no child to scroll. */
  715.  
  716.     x = child->core.x - ((widget == w->viewport.horiz_bar) ? pix : 0);
  717.     y = child->core.y - ((widget == w->viewport.vert_bar) ? pix : 0);
  718.     MoveChild(w, x, y);
  719. }
  720.  
  721.  
  722. /* ARGSUSED */
  723. static void ThumbProc(widget, closure, percent)
  724.     Widget widget;
  725.     caddr_t closure;
  726.     float *percent;
  727. {
  728.     ViewportWidget w = (ViewportWidget)closure;
  729.     register Widget child = w->viewport.child;
  730.     Position x, y;
  731.  
  732.     if (child == NULL) return;    /* no child to scroll. */
  733.  
  734.     if (widget == w->viewport.horiz_bar)
  735. #ifdef macII                /* bug in the macII A/UX 1.0 cc */
  736.     x = (int)(-*percent * child->core.width);
  737. #else /* else not macII */
  738.     x = -(int)(*percent * child->core.width);
  739. #endif /* macII */
  740.     else
  741.     x = child->core.x;
  742.  
  743.     if (widget == w->viewport.vert_bar)
  744. #ifdef macII                /* bug in the macII A/UX 1.0 cc */
  745.     y = (int)(-*percent * child->core.height);
  746. #else /* else not macII */
  747.     y = -(int)(*percent * child->core.height);
  748. #endif /* macII */
  749.     else
  750.     y = child->core.y;
  751.  
  752.     MoveChild(w, x, y);
  753. }
  754.  
  755.  
  756. /* Handle geometry requests from our child.  */
  757.  
  758. static XtGeometryResult
  759. GeometryManager (child, request, reply)
  760.   Widget child;
  761.   XtWidgetGeometry *request, *reply;
  762. {
  763.   XtWidgetGeometry allowed;
  764.   Boolean have_hbar;
  765.   Boolean reconfigured;
  766.   XtGeometryResult result;
  767.   ViewportWidget w = (ViewportWidget) child->core.parent;
  768.   Boolean rWidth = (Boolean) (request->request_mode & CWWidth);
  769.   Boolean rHeight = (Boolean) (request->request_mode & CWHeight);
  770.  
  771.   /* If we're not even being called on our child, forget it.  */
  772.   if (child != w->viewport.child
  773.       /* If we're not allowed to move and/or resize our children, flub it.  */
  774.       || request->request_mode & XtCWQueryOnly
  775.       /* We only handle changes in certain fields; if the request is for 
  776.          other changes, disallow it.  */
  777.       || (request->request_mode & (CWWidth | CWHeight)) == 0)
  778.     return XtGeometryNo;
  779.  
  780.   /* First, try to be the requested size.  If they don't request some
  781.      field, just use the current value.  */
  782.   if (!rWidth)
  783.     request->width = child->core.width;
  784.   if (!rHeight)
  785.     request->height = child->core.height;
  786.  
  787.   reconfigured = GetGeometry (w, request->width, request->height);
  788.  
  789.   /* Initialize the fields we expect to allow according to what we have.  */ 
  790.   allowed.width = w->core.width;
  791.   allowed.height = w->core.height;
  792.   allowed.request_mode = 0;
  793.  
  794.   /* Handle a width change.  */
  795.   if (rWidth)
  796.     {
  797.       allowed.request_mode |= CWWidth;
  798.       
  799.       if (w->core.width < request->width)    /* Need more width?  */
  800.         {
  801.           if (w->viewport.allowhoriz)        /* Can we have a scrollbar?  */
  802.             {
  803.               Widget bar = w->viewport.horiz_bar ? : CreateScrollbar (w, True);
  804.               Dimension bar_height = bar->core.height + bar->core.border_width;
  805.               Dimension new_height = w->core.height + bar_height;
  806.  
  807.               /* Try to accomodate the height of the horizontal bar by
  808.                  increasing our own height.  */
  809.               (void) GetGeometry (w, w->core.width, new_height);
  810.               allowed.request_mode |= CWHeight;
  811.  
  812.               /* In any case, we have a horizontal scrollbar, so now we
  813.                  have less height to give to the child, unless we're
  814.                  allowed to have a vertical scrollbar.  */
  815.               allowed.height = w->viewport.allowvert
  816.                                ? request->height : w->core.height - bar_height;
  817.               allowed.width = request->width;
  818.               reconfigured = True;
  819.               have_hbar = True;
  820.             }
  821.           /* Else we can't have a horizontal scrollbar, but we've been asked
  822.              for more width.  There is nothing left for us to do.  */
  823.         }
  824.       else
  825.         /* The child wants less width.  We can always allow this.  */
  826.         allowed.width = request->width;
  827.     }
  828.   /* Else the child didn't request a width change.  */
  829.  
  830.   /* Handle a height change.  */
  831.   if (rHeight)
  832.     {
  833.       allowed.request_mode |= CWHeight;
  834.       
  835.       if (allowed.height < request->height)    /* Need more height?  */
  836.         {
  837.           if (w->viewport.allowvert)        /* Can we have a scrollbar?  */
  838.             {
  839.               Widget bar = w->viewport.vert_bar ? : CreateScrollbar (w, False);
  840.               Dimension bar_width = bar->core.width + bar->core.border_width;
  841.               Dimension new_width = w->core.width + bar_width;
  842.  
  843.               /* Try to accommodate the width of the vertical bar by
  844.                  increasing our own width.  */
  845.               (void) GetGeometry (w, new_width, w->core.height);
  846.               allowed.request_mode |= CWWidth;
  847.  
  848.               /* In any case, we have a vertical scrollbar, so now we
  849.                  have less width to give to the child, unless we're
  850.                  allowed to have a horizontal scrollbar.  */
  851.               allowed.width = w->viewport.allowhoriz
  852.                               ? request->width : w->core.width - bar_width;
  853.               allowed.height = request->height;
  854.               reconfigured = True;
  855.             }
  856.           else
  857.             {
  858.               /* We can't have a scrollbar, but need more height.  */
  859.               Dimension hbar_height;
  860.  
  861.               /* Since we may have gained some height from a horizontal
  862.                  scrollbar, we need to recompute the height we can give the
  863.                  child.  */
  864.               if (have_hbar)
  865.                 {
  866.                   Widget hbar = w->viewport.horiz_bar;
  867.                   hbar_height = hbar->core.height + hbar->core.border_width;
  868.                 }
  869.               else
  870.                 hbar_height = 0;
  871.  
  872.               allowed.height = w->core.height - hbar_height;
  873.             }
  874.         }
  875.       else
  876.         /* The child wants less height.  We can always allow this.  */
  877.         allowed.height = request->height;
  878.     }
  879.   /* Else the child didn't request a height change.  */
  880.  
  881.   /* If we can't allow what the child wants, return what we can allow.  */
  882.   if ((rWidth && (allowed.width != request->width))
  883.       || (rHeight && (allowed.height != request->height))
  884.       || request->request_mode & ~(CWWidth | CWHeight))
  885.     {
  886.       *reply = allowed;
  887.       result = XtGeometryAlmost;
  888.     }
  889.   else
  890.     {
  891.       if (rWidth)
  892.         child->core.width = request->width;
  893.       if (rHeight)
  894.         child->core.height = request->height;
  895.       result = XtGeometryYes;
  896.       reconfigured = True;
  897.     }
  898.  
  899.   if (reconfigured)
  900.     ComputeLayout (w, /*query:*/ False, /*destroy:*/ result == XtGeometryYes);
  901.   
  902.   return result;
  903. }
  904.  
  905.  
  906. static Boolean GetGeometry(w, width, height)
  907.     Widget w;
  908.     Dimension width, height;
  909. {
  910.     XtWidgetGeometry geometry;
  911.     XtGeometryResult result;
  912.  
  913.     if (width == w->core.width && height == w->core.height)
  914.     return False;
  915.  
  916.     geometry.request_mode = CWWidth | CWHeight;
  917.     geometry.width = width;
  918.     geometry.height = height;
  919.  
  920.     if (!XtIsRealized(w)) {
  921.     /* This is the Realize call; we'll inherit a w&h iff none currently */
  922.     if (w->core.width != 0) {
  923.         if (w->core.height != 0) return False;
  924.         geometry.width = w->core.width;
  925.     }
  926.     if (w->core.height != 0) geometry.height = w->core.height;
  927.     }
  928.     
  929.     result = XtMakeGeometryRequest(w, &geometry, &geometry);
  930.     if (result == XtGeometryAlmost)
  931.     result = XtMakeGeometryRequest(w, &geometry, NULL);
  932.  
  933.     return result == XtGeometryYes;
  934. }
  935.  
  936. static XtGeometryResult PreferredGeometry(w, constraints, reply)
  937.     Widget w;
  938.     XtWidgetGeometry *constraints, *reply;
  939. {
  940.     if (((ViewportWidget)w)->viewport.child != NULL)
  941.     return XtQueryGeometry( ((ViewportWidget)w)->viewport.child,
  942.                    constraints, reply );
  943.     else
  944.     return XtGeometryYes;
  945. }
  946.